﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace engine
{
    public class FuncNode
    {
        public bool IsVar { get; set; }
        public string FuncName { get; set; }
        public List<object> Params { get; set; }
        public VarItem Config { get; set; }
        public Dictionary<string, DataItem> Data { get; set; }
        public FuncNode Parent { get; set; }
        public List<FuncNode> Children { get; set; }
        public ITemplateFunc TemplateFunc { get; protected set; }

        public FuncNode()
        {
            Data = new Dictionary<string, DataItem>();
            Children = new List<FuncNode>();
        }

        public object Run(NodeBase nodeBase, EngineRuntime rt)
        {
            if (IsVar)
            {
                object temp = GetDataValueWithParent(FuncName);
                return temp;
            }
            else
            {
                List<object> handledParams = Params.Select(r => HandleParam(nodeBase, r, FuncType.Render, rt)).ToList();
                handledParams.Insert(0, nodeBase);
                object result = RunFunc(FuncName, handledParams.ToArray());
                return result;
            }
        }

        public void RunForMatch(NodeBase nodeBase, List<Unit> units, EngineRuntime rt = null)
        {
            if (IsVar)
            {
                DataItem value = new DataItem(DefaultMatchData(nodeBase, units), Config);
                SetData(FuncName, value);
            }
            else
            {
                List<object> handledParams = Params.Select(r => HandleParam(nodeBase, r, FuncType.Match, rt)).ToList();
                handledParams.Insert(0, units);
                handledParams.Insert(0, nodeBase);
                RunFunc(FuncName, handledParams.ToArray());
            }
        }

        public object DefaultMatchData(NodeBase nodeBase, List<Unit> units)
        {
            if (units.Count == 0)
            {
                return null;
            }
            else
            {
                if (nodeBase.MappedUnitType == UnitType.TextRange || nodeBase.MappedUnitType == UnitType.Picture)
                {

                    return Matcher(nodeBase, units);
                }
                else if(Config.UnitType == UnitType.Body)
                {
                    foreach(var unit in units)
                    {
                        unit.MatchStatus = MatchStatus.Matched;
                    }
                    return units;
                }
                else
                {
                    units[0].MatchStatus = MatchStatus.Matched;
                    return units[0];
                }
            }
        }

        private object Matcher(NodeBase nodeBase, List<Unit> units)
        {
            DataMatcher dataMatcher = new DataMatcher(nodeBase, units);
            return dataMatcher.Match();
        }

        private object HandleParam(NodeBase nodeBase, object obj, FuncType funcType, EngineRuntime rt)
        {
            if (obj is FuncNode)
            {
                FuncNode funcNode = obj as FuncNode;
                if (funcType == FuncType.Match)
                {
                    var result = GetDataWithParent(funcNode.FuncName);
                    if (result == null)
                    {
                        throw new Exception(string.Format("{0}未定义", funcNode.FuncName));
                    }
                    return result.GetFormatedDataValue();
                }
                else if (funcType == FuncType.Render)
                {
                    var result = funcNode.Run(nodeBase, rt);
                    return result;
                }
                else
                {
                    return obj;
                }
            }
            else
            {
                return obj;
            }
        }



        public DataItem GetDataWithParent(string name)
        {
            if (Data.ContainsKey(name))
            {
                return Data[name];
            }

            if (Parent != null)
            {
                return Parent.GetDataWithParent(name);
            }
            else
            {
                throw new Exception(string.Format("未找到变量{0}", name));
            }
        }

        public object GetDataValueWithParent(string name)
        {
            DataItem dataItem = GetDataWithParent(name);
            if (dataItem != null)
            {
                return dataItem.GetFormatedDataValue();
            }
            else
            {
                return null;
            }
        }

        public object GetDataWithChildren(string name)
        {
            if (Data.ContainsKey(name))
            {
                return Data[name].GetFormatedDataValue();
            }

            foreach (var child in Children)
            {
                var result = child.GetDataWithChildren(name);
                if (result != null)
                {
                    return result;
                }
            }

            return null;
        }

        public Dictionary<string, DataItem> GetDatasWithChildren(TemplateConfig templateConfig)
        {
            Dictionary<string, DataItem> data = new Dictionary<string, DataItem>();

            foreach (var child in Children)
            {
                var temp = child.GetDatasWithChildren(templateConfig);
                foreach (var keyValue in temp)
                {
                    data[keyValue.Key] = keyValue.Value;
                }
            }

            foreach (var keyValue in Data)
            {
                if(templateConfig.Vars.ContainsKey(keyValue.Key) && 
                    keyValue.Value.Config.UnitType == templateConfig.Vars[keyValue.Key].UnitType)
                {
                    data[keyValue.Key] = keyValue.Value;
                }
            }

            return data;
        }

        public void SetData(string name, DataItem value)
        {
            Data[name] = value;
        }

        public void SetDatas(Dictionary<string, DataItem> data)
        {
            Data = data;
        }

        public void AddChild(FuncNode child)
        {
            FuncNode prev = Children.LastOrDefault();
            Children.Add(child);
            child.Parent = this;
        }

        public object RunFunc(string funcName, object[] paras)
        {
            if (TemplateFunc != null && TemplateFunc.HasFunc(funcName))
            {
                return TemplateFunc.Run(funcName, paras);
            }
            else if (Parent != null)
            {
                return Parent.RunFunc(funcName, paras);
            }
            else
            {
                return null;
            }
        }

        public void SetTemplateFunc(ITemplateFunc templateFunc)
        {
            TemplateFunc = templateFunc;
        }
    }

    public class DataItem
    {
        private object Value { get; set; }
        public VarItem Config { get; private set; }

        public DataItem(object value, VarItem config)
        {
            Value = value;
            if (config == null)
            {
                throw new Exception("必须设置有效的数据类型，不能为null");
            }
            Config = config;
        }

        public object GetFormatedDataValue()
        {
            if(Config != null)
            {
                return Config.FormatDataOrDefault(Value);
            }
            else
            {
                return Value;
            }
        }
    }

    public class For
    {
        public FuncNode ListFunc { get; set; }
        public string ItemName { get; set; }
        public string IndexName { get; set; }

        public void Run(NodeBase parent, Action<List<object>, object, int> action)
        {
            List<object> list = ListFunc.Run(parent, null) as List<object>;
            if (list == null)
            {
                throw new Exception("不存在可遍历值");
            }

            ArrayVarItem objectVarItem = ListFunc.Config as ArrayVarItem;
            TypeItem typeItem = null;
            if (objectVarItem == null)
            {
                typeItem = null;
            }
            else
            {
                typeItem = objectVarItem.CustomType;
            }
            for (int i = 0; i < list.Count; i++)
            {
                parent.FuncNode.SetData(ItemName, new DataItem(list[i], new ObjectVarItem(typeItem)));
                if (!string.IsNullOrWhiteSpace(IndexName))
                {
                    parent.FuncNode.SetData(IndexName, new DataItem(i, new NumberVarItem()));
                }
                action(list, list[i], i);
            }
        }

        public void RunForMatch(NodeBase parent, List<Unit> units, Action<Unit> action)
        {
            List<object> list = new List<object>();
            parent.FuncNode.SetData(ListFunc.FuncName, new DataItem(list, ListFunc.Config));

            ArrayVarItem arrayVarItem = ListFunc.Config as ArrayVarItem;
            foreach (var unit in units)
            {
                var item = new DataItem(new Dictionary<string, object>(), arrayVarItem.CustomType.DefaultConfig);
                parent.FuncNode.SetData(ItemName, item);
                action(unit);
                var temp = parent.FuncNode.GetDataWithChildren(ItemName);
                list.Add(temp);
            }
        }
    }

    public class GlobalConfig
    {
        public FuncNode RootFuncNode { get; set; }
        public TemplateConfig TemplateConfig { get; set; }

        public GlobalConfig()
        {
            RootFuncNode = new FuncNode();
        }
    }
}
